#pragma once
#include <src/math/BoundaryCondition/BoundaryCondition.h>
#include <src/math/Operators/all.h>
#include <src/math/functor/GaussianFunctor.h>
#include <src/math/functor/2D_representation.h>


template<class Operator, std::size_t Dim = Operator::result_type::Dim, typename Family = Operator::Family_Operator>
	struct return_test {
		typedef particle<typename Operator::result_type::base_value_type>		p_array_1;
		typedef particles_list<p_array_1>										p_array_2;
		p_array_2 operator()() {
			OS_STATIC_CHECK(false); // to implement
			return p_array_2;
		};
};

template<class Operator>
	struct return_test<Operator,2,Particle_Operator> {
		typedef particle<typename Operator::result_type::base_value_type>		p_array_1;
		typedef particles_list<p_array_1>										p_array_2;
		p_array_2 operator()() {
			typedef typename Operator::result_type			data;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Particle Operator_example Dim 3-------" << std::endl;
			std::cout << std::endl << " --------type of Operator : " << Operator::get_name() << std::endl;
			std::cout << std::endl << " --------type of data : " << data::get_name() << data::Boundary_type::get_name() << std::endl;

			data gaussian = InverseCumulativeFunctor<data>()(8,3);

			std::cout << "Three dimensional random gaussian Vector of 8 particles" << gaussian << std::endl;
			Operator		Op_Delta;
			Op_Delta.set_state_variable(smart_ptr<data> (new data(gaussian)) );
			std::cout << std::endl << " -------Operator graph is  -----" << std::endl;
			std::cout << Op_Delta;
			data gaussian_laplacian = Op_Delta(gaussian);
			std::cout << "Operator Applied to A is " << Op_Delta(gaussian) << std::endl;

			p_array_2 p = representation_2<data,Operator::Dim,Operator::Family_Operator>()(gaussian_laplacian);

			std::cout << std::endl << " -------End Operator_example returning a 2D representation -----" << std::endl;
			std::cout << std::endl << " -------of the operator applied to a 10 points gaussian vector---" << std::endl;
			return p;
		};
};

template<class Operator>
	struct return_test<Operator,2,Finite_Diff_Operator> {
		typedef particle<typename Operator::result_type::base_value_type>		p_array_1;
		typedef particles_list<p_array_1>										p_array_2;
		p_array_2 operator()() {
			typedef typename Operator::result_type			data;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Particle Operator_example Dim 3-------" << std::endl;
			std::cout << std::endl << " --------type of Operator : " << Operator::get_name() << std::endl;
			std::cout << std::endl << " --------type of data : " << data::get_name() << data::Boundary_type::get_name() << std::endl;

			typedef  data::value_type value_type;
			data gaussian_test(2,8);
			gaussian_test[0] = InverseCumulativeFunctor<value_type>()(8);
			gaussian_test[1] = gaussian_test[0] /2.;
			data gaussian(2,8);
			gaussian[0] = gaussian_test[1];
			gaussian[1] = gaussian_test[0];

			std::cout << "Two dimensional random gaussian Vector of 8 particles" << gaussian_test << std::endl;
			std::cout << "Two dimensional random gaussian Vector of 8 particles" << gaussian << std::endl;
			Operator		Op_Delta;
			Op_Delta.set_state_variable(smart_ptr<data> (new data(gaussian)) );
			std::cout << std::endl << " -------Operator graph is  -----" << std::endl;
			std::cout << Op_Delta;
			data gaussian_laplacian = Op_Delta(gaussian);
			std::cout << "Operator Applied to A is " << Op_Delta(gaussian) << std::endl;

			p_array_2 p = representation_2<data,2,Operator::Family_Operator>()(gaussian_laplacian);

			std::cout << std::endl << " -------End Operator_example returning a 2D representation -----" << std::endl;
			std::cout << std::endl << " -------of the operator applied to a 10 points gaussian vector---" << std::endl;
			return p;
		};
};



template<class Operator>
	struct return_test<Operator,1,Particle_Operator> {
		typedef particle<typename Operator::result_type::base_value_type>		p_array_1;
		typedef particles_list<p_array_1>										p_array_2;
		p_array_2 operator()() {
			typedef typename Operator::result_type			data;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Particle Operator_example Dim 1-------" << std::endl;
			std::cout << std::endl << " --------type of Operator : " << Operator::get_name() << std::endl;
			std::cout << std::endl << " --------type of data : " << data::get_name() << data::Boundary_type::get_name() << std::endl;

			data gaussian = InverseCumulativeFunctor<data>()(10);

			std::cout << "One dimensional random gaussian Vector of 8 particles" << gaussian << std::endl;
			Operator		Op_Delta;
			Op_Delta.set_state_variable(smart_ptr<data> (new data(gaussian)) );
			std::cout << std::endl << " -------Operator graph is  -----" << std::endl;
			std::cout << Op_Delta.get_graph();
			data gaussian_laplacian = Op_Delta(gaussian);
			std::cout << "Operator Applied to the previous vector is " << gaussian_laplacian << std::endl;

			p_array_2 p = representation_2<data,1,Operator::Family_Operator>()(gaussian_laplacian);

			std::cout << std::endl << " -------End Operator_example returning a 2D representation -----" << std::endl;
			std::cout << std::endl << " -------of the operator applied to a 10 points gaussian vector---" << std::endl;
			return p;
		};
};




template<class Operator>
	struct return_test<Operator,1,Finite_Diff_Operator> {
		typedef particle<typename Operator::result_type::base_value_type>		p_array_1;
		typedef particles_list<p_array_1>										p_array_2;
		p_array_2 operator()() {
			typedef typename Operator::result_type			data;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Finitie Diff Operator_example 1D-------" << std::endl;
			std::cout << std::endl << " --------type of Operator : " << Operator::get_name() << std::endl;
			std::cout << std::endl << " --------type of data : " << data::get_name() << data::Boundary_type::get_name() << std::endl;


			data A(4);
			for (OS_int i = 0; i<A.size();++i)
					A[i] = i;


			Operator		Op_Delta;
			typedef Operator::state_variable_type state_variable_type;
			Op_Delta.set_state_variable(smart_ptr<data> (new data(A)) );
			std::cout << "One dimensional Mod Vector A{4}" << A << std::endl;
			std::cout << "Operator Applied to A{4} is " << Op_Delta(A) << std::endl;

			data* gaussian = new data(Gaussian_Functor<data>()(10));
			Op_Delta.set_state_variable(smart_ptr<data> (gaussian) );
			data gaussian_laplacian = Op_Delta(*gaussian);
			p_array_2 p = representation_2<data,1,Operator::Family_Operator>()(gaussian_laplacian);

			std::cout << std::endl << " -------Operator graph is  -----" << std::endl;
			std::cout << Op_Delta;

			std::cout << std::endl << " -------End Operator_example returning a 2D representation -----" << std::endl;
			std::cout << std::endl << " -------of the operator applied to a 10 points gaussian vector---" << std::endl;
			return p;
		};
};




template <class Operator1, class Operator2> 
void check_operator () {
		typedef particle<typename Operator1::result_type::base_value_type>		p_array_1;
		typedef particles_list<p_array_1>										p_array_2;
		p_array_2 p_mod1 = return_test<Operator1>()();
		p_array_2 p_mod2 = return_test<Operator2>()();
		bool logical = p_mod1 == p_mod2;
		OS_DYNAMIC_CHECK(logical == true, "check_operator : An operator computed over periodic data depends on data definition");
};



	void Operators_test ();
